//
//  JJServiceFactory.swift
//  swiftStudy
//
//  Created by Alpha on 2020/6/24.
//  Copyright © 2020 Alpha. All rights reserved.
//

import Foundation

class JJServiceFactory {
    var checkIntervalOfUnloadingService = 600
    
    private var _loginSuccessNotificationNameArray:[String] = []
    private var _logoutNotificationNameArray:[String] = []
    
    private var _serviceContainer:[String: JJService] = [:]
    private let _lock:DispatchSemaphore = DispatchSemaphore(value: 1)
    private var _beginDateOfUnloadingService = Date()
    
    static let shared = JJServiceFactory()
    
    private init() {
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    func getService(serviceName serviceName_: String) -> JJService {
        self._beginLock()
        
        var service = self._serviceContainer[serviceName_]
        if (service != nil) {
            self._endLock()
            return service!
        }
        
        let timeInterval = Date().timeIntervalSince(self._beginDateOfUnloadingService)
        let isNeedUnload = Int(timeInterval) > self.checkIntervalOfUnloadingService
        if (isNeedUnload) {
            self._unloadUnneededServiceWithNoLock()
            self._beginDateOfUnloadingService = Date()
        }
        
        let appName = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String
        let serviceClass = NSClassFromString(appName + "." + serviceName_) as! JJService.Type
        service = serviceClass.init()
        
        service!.willLoad()
        self._serviceContainer[serviceName_] = service
        service!.didLoad()
        
        self._endLock()
        return service!
    }
    
    func unloadService(serviceName serviceName_: String) -> Bool {
        return self.unloadService(serviceName: serviceName_, isForceUnload: false)
    }
    
    func unloadService(serviceName serviceName_: String, isForceUnload isForceUnload_: Bool) -> Bool {
        self._beginLock()
        
        let service = self._serviceContainer[serviceName_]
        if (nil == service) {
            return false
        }
        
        if (!isForceUnload_ && !service!.needUnloading()) {
            self._endLock()
            return false
        }
        
        service!.willLoad()
        self._serviceContainer.removeValue(forKey: serviceName_)
        service!.didLoad()
        
        self._endLock()
        return true
    }
    
    func _unloadUnneededServiceWithNoLock() -> Void {
        
        let container = self._serviceContainer.filter { (key: String, value: JJService) -> Bool in
            return !value.needUnloading()
        }
        
        self._serviceContainer = container
    }
    
    func setLoginSuccessNotificationNameArray(names names_: [String]) -> Void {
        for name in self._loginSuccessNotificationNameArray {
            NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: name), object: nil)
        }
        
        self._loginSuccessNotificationNameArray = names_
        
        for name in self._loginSuccessNotificationNameArray {
            NotificationCenter.default.addObserver(self, selector: NSSelectorFromString("_loginSuccessNotification:"), name: NSNotification.Name(rawValue: name), object: nil)
        }
    }
    
    func setLogoutNotificationNameArray(names names_: [String]) -> Void {
        for name in self._logoutNotificationNameArray {
            NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: name), object: nil)
        }
        
        self._logoutNotificationNameArray = names_
        
        for name in self._logoutNotificationNameArray {
            NotificationCenter.default.addObserver(self, selector: NSSelectorFromString("_logoutNotification:"), name: NSNotification.Name(rawValue: name), object: nil)
        }
    }
    
    private func _loginSuccessNotification(notification: Notification) -> Void {
        self._beginLock()
        
        for service in self._serviceContainer.values {
            service.actionAfterLogin(notification.userInfo)
        }
        
        self._endLock()
    }
    
    private func _logoutNotification(notification: Notification) -> Void {
        self._beginLock()
        
        for service in self._serviceContainer.values {
            service.actionAfterLogout(notification.userInfo)
        }
        
        self._endLock()
    }
    
    private func _beginLock() -> Void {
        self._lock.wait()
    }
    
    private func _endLock() -> Void {
        self._lock.signal()
    }
}
